<?php
/**
 * 
 * @todo description of this class
 * 
 * @author Alton Crossley <crossleyframework@nogahidebootstrap.com>
 * @package Crossley Framework
 *  
 * @copyright Copyright (c) 2003-2009, Nogaide BootStrap INC. All rights reserved.
 * @license BSD http://opensource.org/licenses/bsd-license.php
 * @version $Id:$
 * 
 */
class X_Dom_Calendar extends XMLWriter 
{
    public $aDayTitles = array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
    public $aDayClasses = array('sunday weekend', 'monday weekday', 'tuesday weekday', 'wednesday weekday', 'thursday weekday', 'friday weekday', 'saturday weekday');
    /**
     * unix time stamp for the first day to display
     *
     * @var X_Date
     */
    protected $_oStartDate;
    /**
     * unix time stamp of the last day to display
     *
     * @var X_Date
     */    
    protected $_oEndDate;
    /**
     * attributes applied to all columns via the colgroup tag.
     *
     * @var array
     */
    protected $_aColumnAttributes;
    
    protected $_aEvents = array();
    
    function __construct($sID = 'x_calendar', $iBorder = 0)
    {
        $this->openMemory();
        $this->startElement('table'); 
        $this->writeAttribute('border', $iBorder);
        $this->writeAttribute('id', $sID);
    }
    
    /**
     * @return X_Date
     */
    public function getEndDate()
    {
        return $this->_oEndDate;
    }
    
    /**
     * @param X_Date $_EndDate
     */
    public function setEndDate($oEndDate)
    {
    	if ($oEndDate instanceof Zend_Date)
    	{
    		$oEndDate = new X_Date((string)$oEndDate);
    	}
        $this->_oEndDate = $oEndDate;
    }
    
    /**
     * @return X_Date
     */
    public function getStartDate()
    {
        return $this->StartDate;
    }
    

    /**
     * @param X_Date $_oStartDate
     */
    public function setStartDate($oStartDate)
    {
    	if ($oStartDate instanceof Zend_Date)
    	{
    		$oStartDate = new X_Date((string)$oStartDate);
    	}
        $this->_oStartDate = $oStartDate;
    }
    
    public function addEvent($sDate, $sContent)
    {
        $sKey = $this->_dateFromString($sDate);
        
        if (array_key_exists($sKey, $this->_aEvents))
        {
            $this->_aEvents[$sKey][] = $sContent;
        }
        else
        {
            $this->_aEvents[$sKey] = array($sContent);
        }
        
    }
    
    public function getEvents($sDate)
    {
        $sKey = $this->_dateFromString($sDate);
        if (array_key_exists($sKey, $this->_aEvents))
        {
            return $this->_aEvents[$sKey];            
        }
        else
        {
            return array();
        }
    }
    
    /**
     * get a unix time stamp from a date string
     * Localized via X_Date
     *
     * @param string $sDate
     * @return unix timestap
     */
    protected function _dateFromString($sDate)
    {
        $oDate = new X_Date($sDate);
        return $oDate->getTimestamp();
    }

    protected function _renderEmptyTd($iCount)
    {
        for ($i=0; $i<$iCount; $i++)
        {
            $this->startElement('td');
            $this->writeRaw('&nbsp;');
            $this->endElement(); 
        }
    }
    
    
    protected function _renderHead()
    {
        $this->startElement('caption');
            $this->writeRaw('<span class="calendar_next">Next 	&gt;&gt;</span>'); // this is meant to be floated
            $this->writeRaw('<span class="calendar_previous">&lt;&lt; Previous</span>'); // this is meant to be floated
            $this->writeRaw('<h2>'.$this->_oStartDate->toString('F Y', 'php').'</h2>');
        $this->endElement(); 
    
        $this->startElement('thead');
            $this->startElement('tr');
            foreach ($this->aDayTitles as $iKey => $sTitle)
            {
                $this->startElement('td');
                $this->writeAttribute('class', $this->aDayClasses[$iKey]);
                $this->text($sTitle);
                $this->endElement(); 
            }
            $this->endElement(); 
        $this->endElement(); 
    }
    
    protected function _padPrefix()
    {
        $iDays = $this->_oStartDate->toString('N', 'php')                                                                                                            ;
        $this->_renderEmptyTd($iDays);
    }
    
    protected function _renderDay($oDate)
    {
        $this->startElement('td');
        
        $sDayContent = sprintf('<span>%s</span>%s',
            $oDate->toString('d', 'php'),
            implode('', $this->getEvents($oDate)));
            
        $this->writeRaw($sDayContent);
        $this->endElement();
    }
    
    public function setColumnAttribute($sName, $sValue)
    {
        $this->aDayClasses_aColumnAttributes[$sName] = $sValue;
    }
    
    /**
     * sets the start and end date to the beginning and end of the month
     */
    public function showMonth()
    {
    	$this->_oStartDate->setDayOfMonth(1);
    	$this->_oEndDate->setLastDayOfMonth();
    }
    
    protected function _renderColumns()
    {
        $sElement = 'colgroup';
        if (!empty($this->aDayClasses_aColumnAttributes))
        {
            for ($i=0; $i <= 7; $i++)
            {
//                colgroup
                $this->startElement($sElement);
                foreach ($this->aDayClasses_aColumnAttributes as $sName => $sValue)
                {
                    $this->writeAttribute($sName, $sValue);                                    
                }
                $this->endElement();
            }
        }
    }
    
    protected function _renderBody()
    {
    	// start the body
        $this->startElement('tbody');
        // create column groups
        $this->_renderColumns();
        
        // set the row element to TR
        $this->startElement('tr');
        // render empty cells
        $this->_padPrefix();
        
        // create a date to track rows
        $oDays = new X_Date((string)$this->_oStartDate->toString('m/d/Y', 'php') . ' 00:00:00');
        $oEndDate = new X_Date($this->_oEndDate->toString('m/d/Y', 'php') . ' 00:00:00');
        $oEndDate->addDay();
        
        // as long as the current date is earlier than the end date - continue
//		        print X_Debug::out($oDays, '$oDays ' . $oDays->toString('m/d/Y', 'php'));
		//        print X_Debug::out($this->_oEndDate, '$this->_oEndDate');
		//        print X_Debug::out("(" . $this->_oEndDate->getTimestamp() . " < " . $oDays->getTimestamp() . ")");
		//        print X_Debug::out("(" . $this->_oEndDate->toString('m/d/y') . " < " . $oDays->toString('m/d/y') . ")");

//		print X_Debug::out('start:' . $this->_oStartDate->toString('m/d/Y', 'php') . ' - end:' . $this->_oEndDate->toString('m/d/Y', 'php'));
//		print X_Debug::out('start day number: ' . $oDays->toString('N', 'php'));
//		print X_Debug::out('is Earlier : (' . $this->_oEndDate->toString('m/d/Y', 'php') . '<' . $oDays->toString('m/d/Y', 'php') . '):' . $oDays->isEarlier((string)$this->_oEndDate));
		
        while ($oDays->isEarlier($oEndDate->toString('m/d/Y', 'php') . ' 00:00:00'))
        {
            // if we just rendered Sunday, start a new row
            if ($oDays->toString('N', 'php') == 7)
            {
                $this->endElement();
                $this->startElement('tr');
            }
            
            $this->_renderDay($oDays);
            
            $oDays->addDay(1);
        }
        
        $this->_renderEmptyTd(7-(int)$oDays->toString('N', 'php'));
        
        // end tr
        $this->endElement();

        // end tbody
        $this->endElement(); 
    }
    
    protected function _renderFooter()
    {
        $this->startElement('tfoot');
            $this->startElement('tr');
            // put td here
            $this->endElement(); 
        $this->endElement(); 
    }
    
    function __toString()
    {
        $this->_renderHead();
        $this->_renderBody();
        $this->_renderFooter();
        
        $this->endElement(); 
        $this->endDocument(); 
        return $this->flush();         
    }

}